from django.db import models
from django.utils import timezone
from django_ckeditor_5.fields import CKEditor5Field
from django.contrib.auth.hashers import make_password
from django.core.exceptions import ValidationError
import os
from datetime import datetime, timedelta

class ExamNotification(models.Model):
    """考场通知表"""
    NOTIFICATION_TYPE_CHOICES = [
        ('status_change', '状态变更'),
        ('system', '系统通知'),
    ]

    exam_room = models.ForeignKey('ExamRoom', on_delete=models.CASCADE, verbose_name="考场")
    examinee = models.ForeignKey('Examinee', on_delete=models.CASCADE, verbose_name="考生")
    notification_type = models.CharField(max_length=20, choices=NOTIFICATION_TYPE_CHOICES, verbose_name="通知类型")
    title = models.CharField(max_length=200, verbose_name="通知标题")
    content = models.TextField(verbose_name="通知内容")
    created_at = models.DateTimeField(auto_now_add=True, verbose_name="创建时间")
    is_read = models.BooleanField(default=False, verbose_name="是否已读")

    class Meta:
        verbose_name = "考场通知"
        verbose_name_plural = "考场通知"
        ordering = ['-created_at']

    def __str__(self):
        return f"{self.exam_room.name} - {self.title}"

class Subject(models.Model):
    name = models.CharField(max_length=100, unique=True, verbose_name="科目名称")
    description = models.TextField(blank=True, null=True, verbose_name="科目描述")
    created_at = models.DateTimeField(auto_now_add=True, verbose_name="创建时间")
    updated_at = models.DateTimeField(auto_now=True, verbose_name="更新时间")

    class Meta:
        verbose_name = "科目"
        verbose_name_plural = "科目"
        ordering = ['name']

    def __str__(self):
        return self.name

class Question(models.Model):
    class Meta:
        verbose_name = "题库"
        verbose_name_plural = verbose_name
        ordering = ['-update_time']

    QUESTION_TYPE_CHOICES = [
        ('single', '单选题'),
        ('multiple', '多选题'),
        ('judge', '判断题'),
    ]

    DIFFICULTY_CHOICES = [
        ('easy', '易'),
        ('medium', '中'),
        ('hard', '难'),
    ]

    subject = models.ForeignKey(Subject, on_delete=models.CASCADE, verbose_name="科目", related_name="questions")
    content = CKEditor5Field(verbose_name="题干", help_text="请输入题目内容", config_name='extends')
    question_type = models.CharField(
        max_length=10,
        choices=QUESTION_TYPE_CHOICES,
        default='single',
        verbose_name="题型"
    )
    options = models.TextField(max_length=1024, blank=True, null=True, verbose_name="选项", help_text="请输入选项，每个选项一行")
    difficulty = models.CharField(
        max_length=10,
        choices=DIFFICULTY_CHOICES,
        default='medium',
        verbose_name="难度"
    )
    answer = models.CharField(max_length=100, verbose_name="答案", help_text="请输入正确答案")
    image = models.ImageField(upload_to='question_images/', blank=True, null=True, verbose_name="本题图片")
    image_name = models.CharField(max_length=255, blank=True, null=True, verbose_name="本题图片名")
    creator = models.CharField(max_length=100, blank=True, null=True, verbose_name="出题人")
    create_time = models.DateTimeField(auto_now_add=True, verbose_name="创建时间")
    update_time = models.DateTimeField(auto_now=True, verbose_name="更新时间")

    def __str__(self):
        return f"{self.subject}-{self.question_type}-{self.content[:20]}"

    def save(self, *args, **kwargs):
        if not self.creator:
            self.creator = "管理员"

        # 自动填充图片名
        if self.image:
            self.image_name = os.path.basename(self.image.name)
        else:
            self.image_name = None

        super().save(*args, **kwargs)

    def delete(self, *args, **kwargs):
        # 删除关联的图片文件
        if self.image:
            if os.path.isfile(self.image.path):
                os.remove(self.image.path)
        super().delete(*args, **kwargs)

class ExamRoom(models.Model):
    """考场信息表"""
    STATUS_CHOICES = [
        ('preparing', '准备中'),
        ('in_progress', '考试中'),
        ('finished', '已结束'),
        ('cancelled', '已取消'),
    ]

    name = models.CharField(max_length=100, verbose_name="考场名称")
    subject_1 = models.ForeignKey(
        Subject,
        on_delete=models.PROTECT,
        verbose_name="科目一",
        related_name='exam_rooms_subject_1'
    )
    subject_2 = models.ForeignKey(
        Subject,
        on_delete=models.PROTECT,
        verbose_name="科目二",
        related_name='exam_rooms_subject_2',
        null=True,
        blank=True
    )
    subject_3 = models.ForeignKey(
        Subject,
        on_delete=models.PROTECT,
        verbose_name="科目三",
        related_name='exam_rooms_subject_3',
        null=True,
        blank=True
    )
    exam_type = models.CharField(max_length=50, verbose_name="考试类别", default='普通考试')

    start_time = models.DateTimeField(verbose_name="开始时间")
    duration = models.IntegerField(verbose_name="考试时长(分钟)")
    invigilators = models.CharField(max_length=200, verbose_name="监考人员")

    # 题目配置
    single_choice_count = models.PositiveIntegerField(verbose_name="单选题数量", default=0)
    single_choice_score = models.DecimalField(max_digits=5, decimal_places=2, verbose_name="单选题分值", default=0)
    multiple_choice_count = models.PositiveIntegerField(verbose_name="多选题数量", default=0)
    multiple_choice_score = models.DecimalField(max_digits=5, decimal_places=2, verbose_name="多选题分值", default=0)
    judgment_count = models.PositiveIntegerField(verbose_name="判断题数量", default=0)
    judgment_score = models.DecimalField(max_digits=5, decimal_places=2, verbose_name="判断题分值", default=0)

    # 考试统计
    total_score = models.DecimalField(max_digits=6, decimal_places=2, verbose_name="考试总分",
                                    help_text="自动计算：单选题分值×数量 + 多选题分值×数量 + 判断题分值×数量",
                                    null=True, blank=True, default=0,
                                    editable=False)  # 设置为不可编辑，由系统自动计算
    average_score = models.DecimalField(max_digits=6, decimal_places=2, verbose_name="考试平均分",
                                      null=True, blank=True)
    status = models.CharField(max_length=20, choices=STATUS_CHOICES, default='preparing',
                            verbose_name="考场状态")

    # 创建和更新时间
    created_at = models.DateTimeField(auto_now_add=True, verbose_name="创建时间")
    updated_at = models.DateTimeField(auto_now=True, verbose_name="更新时间")

    class Meta:
        verbose_name = "考场"
        verbose_name_plural = "考场"
        ordering = ['-start_time']

    def __str__(self):
        return f"{self.name} ({self.get_status_display()})"

    def save_status(self, *args, **kwargs):

        if self.pk:
            ExamRoom.objects.get(pk=self.pk)

        # 保存实例
        super().save(*args, **kwargs)

    def save(self, *args, **kwargs):

        # 自动计算总分
        self.total_score = (
            self.single_choice_count * float(self.single_choice_score) +
            self.multiple_choice_count * float(self.multiple_choice_score) +
            self.judgment_count * float(self.judgment_score)
        )

        # 在保存前执行完整性验证
        self.full_clean()

        # 保存实例
        super().save(*args, **kwargs)

    @property
    def end_time(self):
        """计算考试结束时间"""
        if self.start_time:
            return self.start_time + timedelta(minutes=self.duration)
        return None

    def check_questions_availability(self):
        """检查题库中是否有足够的题目"""
        subjects = [self.subject_1]
        if self.subject_2:
            subjects.append(self.subject_2)
        if self.subject_3:
            subjects.append(self.subject_3)

        error_messages = []

        # 检查各类型题目数量
        question_types = {
            'single': {'count': self.single_choice_count, 'name': '单选题'},
            'multiple': {'count': self.multiple_choice_count, 'name': '多选题'},
            'judge': {'count': self.judgment_count, 'name': '判断题'}
        }

        for q_type, data in question_types.items():
            if data['count'] > 0:
                available_count = Question.objects.filter(
                    subject__in=subjects,
                    question_type=q_type
                ).count()

                if available_count < data['count']:
                    error_messages.append(
                        f"{data['name']}数量不足：需要{data['count']}道，题库中只有{available_count}道"
                    )

        return error_messages

    def clean(self, *args, **kwargs):
        """模型验证"""
        super().clean()

        # 检查题目数量
        if self.status != 'finished':  # 只在考试未结束时检查
            error_messages = self.check_questions_availability()
            if error_messages:
                raise ValidationError({
                    'single_choice_count': error_messages
                })

    @property
    def is_active(self):
        """判断考场是否在进行中"""
        if self.status != 'in_progress':
            return False
        now = timezone.now()
        # 确保考试时间已经开始且未结束
        return self.start_time <= now <= self.end_time

    def get_status_display(self):
        # 根据当前状态返回对应的显示文本
        if self.status == 'preparing':
            return '准备中'
        elif self.status == 'in_progress':
            return '考试中'
        elif self.status == 'finished':
            return '已结束'
        elif self.status == 'cancelled':
            return '已取消'

class ExamPaper(models.Model):
    """试卷信息表"""
    exam_room = models.ForeignKey(ExamRoom, on_delete=models.CASCADE, verbose_name="考场")
    examinee = models.ForeignKey('Examinee', on_delete=models.CASCADE, verbose_name="考生")
    created_at = models.DateTimeField(auto_now_add=True, verbose_name="出卷时间")
    total_score = models.DecimalField(max_digits=6, decimal_places=2, verbose_name="得分", default=0)
    is_submitted = models.BooleanField(default=False, verbose_name="是否提交")
    submitted_at = models.DateTimeField(null=True, blank=True, verbose_name="提交时间")
    last_active_time = models.DateTimeField(auto_now=True, verbose_name="最后活动时间")

    class Meta:
        verbose_name = "试卷"
        verbose_name_plural = "试卷"
        ordering = ['-created_at']
        # 确保同一考生在同一考场只有一份试卷
        unique_together = ['exam_room', 'examinee']

    def __str__(self):
        return f"{self.exam_room.name}-{self.examinee.name}的试卷"

    @classmethod
    def generate_paper(cls, exam_room, examinee):
        """生成试卷"""
        # 创建试卷
        paper = cls.objects.create(
            exam_room=exam_room,
            examinee=examinee
        )

        # 获取考场对应的科目
        subjects = [exam_room.subject_1]
        if exam_room.subject_2:
            subjects.append(exam_room.subject_2)
        if exam_room.subject_3:
            subjects.append(exam_room.subject_3)

        # 按题型抽题
        question_configs = [
            ('single', exam_room.single_choice_count, exam_room.single_choice_score),
            ('multiple', exam_room.multiple_choice_count, exam_room.multiple_choice_score),
            ('judge', exam_room.judgment_count, exam_room.judgment_score)
        ]

        question_number = 1
        for q_type, count, score in question_configs:
            if count > 0:
                # 从所有相关科目中随机抽取指定数量的题目
                questions = Question.objects.filter(
                    subject__in=subjects,
                    question_type=q_type
                ).order_by('?')[:count]

                # 创建试题记录
                for question in questions:
                    ExamQuestion.objects.create(
                        paper=paper,
                        question=question,
                        question_number=question_number,
                        score=score
                    )
                    question_number += 1

        return paper

class ExamQuestion(models.Model):
    """试卷题目关联表"""
    paper = models.ForeignKey(ExamPaper, on_delete=models.CASCADE, verbose_name="试卷", related_name='questions')
    question = models.ForeignKey(Question, on_delete=models.PROTECT, verbose_name="试题")
    question_number = models.PositiveIntegerField(verbose_name="题号")
    score = models.DecimalField(max_digits=5, decimal_places=2, verbose_name="分值")
    answer = models.CharField(max_length=100, blank=True, null=True, verbose_name="考生答案")
    is_correct = models.BooleanField(null=True, verbose_name="是否正确")
    answer_time = models.DateTimeField(null=True, blank=True, verbose_name="答题时间")

    class Meta:
        verbose_name = "试卷题目"
        verbose_name_plural = "试卷题目"
        ordering = ['paper', 'question_number']
        unique_together = ['paper', 'question_number']

    def __str__(self):
        return f"{self.paper}-第{self.question_number}题"

    def submit_answer(self, answer):
        """提交答案"""
        # 保存之前的正确状态
        was_correct = self.is_correct

        # 清除可能的空格并转换为大写
        answer = answer.strip().upper() if answer else ""
        correct_answer = self.question.answer.strip().upper()

        self.answer = answer
        self.answer_time = timezone.now()

        # 对于多选题，需要特殊处理
        if self.question.question_type == 'multiple':
            # 分割答案并排序再join成字符串，以确保顺序无关
            submitted_parts = ''.join(answer.replace(',','')) if answer else ''
            correct_parts = ''.join(sorted(correct_answer)) if correct_answer else ''
            self.is_correct = submitted_parts == correct_parts
        else:
            # 单选题和判断题直接比较
            self.is_correct = answer == correct_answer

        self.save()

        # 更新试卷总分
        # 如果状态从错误变为正确，增加分数
        if not was_correct and self.is_correct:
            self.paper.total_score = float(self.paper.total_score) + float(self.score)
            self.paper.save()
        # 如果状态从正确变为错误，减少分数
        elif was_correct and not self.is_correct:
            self.paper.total_score = max(0, float(self.paper.total_score) - float(self.score))
            self.paper.save()

class ExamRegistration(models.Model):
    """考试报名记录"""
    examinee = models.ForeignKey('Examinee', on_delete=models.CASCADE, verbose_name="考生")
    exam_room = models.ForeignKey(ExamRoom, on_delete=models.CASCADE, verbose_name="考场")
    register_time = models.DateTimeField(auto_now_add=True, verbose_name="报名时间")
    status = models.CharField(
        max_length=20,
        choices=[
            ('registered', '已报名'),
            ('cancelled', '已取消'),
            ('completed', '已完成'),
        ],
        default='registered',
        verbose_name="状态"
    )

    class Meta:
        verbose_name = "考试报名"
        verbose_name_plural = "考试报名"
        ordering = ['-register_time']
        unique_together = ['examinee', 'exam_room']

    def __str__(self):
        return f"{self.examinee.name}-{self.exam_room.name}"

class Examinee(models.Model):
    """考生信息表"""
    GENDER_CHOICES = [
        ('M', '男'),
        ('F', '女'),
        ('O', '其他'),
    ]

    phone = models.CharField(max_length=20, unique=True, verbose_name="手机号")
    name = models.CharField(max_length=50, verbose_name="姓名")
    nickname = models.CharField(max_length=50, blank=True, null=True, verbose_name="昵称")
    gender = models.CharField(max_length=1, choices=GENDER_CHOICES, blank=True, null=True, verbose_name="性别")
    password = models.CharField(max_length=128, verbose_name="密码")
    email = models.EmailField(blank=True, null=True, verbose_name="邮箱")
    organization = models.CharField(max_length=100, blank=True, null=True, verbose_name="所在单位")
    id_card = models.CharField(max_length=18, blank=True, null=True, verbose_name="身份证号")
    register_time = models.DateTimeField(auto_now_add=True, verbose_name="注册时间")
    last_login = models.DateTimeField(blank=True, null=True, verbose_name="最后登录时间")

    class Meta:
        verbose_name = "考生"
        verbose_name_plural = "考生"
        ordering = ['-register_time']

    def __str__(self):
        return f"{self.name} ({self.phone})"

    def save(self, *args, **kwargs):
        # 如果是新创建的用户或密码被修改了，则对密码进行哈希处理
        if not self.pk or 'password' in kwargs.get('update_fields', []):
            self.password = make_password(self.password)
        super().save(*args, **kwargs)